package org.rpc.service;

import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.rpc.common.RpcInvocation;
import org.rpc.common.RpcProtocol;

import java.lang.reflect.Method;

import static org.rpc.common.cache.CommonServerCache.PROVIDER_CLASS_MAP;

public class ServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 强制转换，上一个处理器已经把数据转换为本对象了
        RpcProtocol rpcProtocol = (RpcProtocol) msg;
        // 获取协议中的content字段的所有数据
        String json = new String(rpcProtocol.getContent(), 0, rpcProtocol.getContentLength());
        // 具体在服务侧需要执行的内容，以RpcInvocation数据结构封装
        RpcInvocation rpcInvocation = JSON.parseObject(json, RpcInvocation.class);
        // 从缓存中获取，查看当前是否有这个接口
        Object aimObject = PROVIDER_CLASS_MAP.get(rpcInvocation.getTargetServiceName());
        // 当前接口中的方法
        Method[] methods = aimObject.getClass().getDeclaredMethods();
        Object result = null;
        // 流程执行完毕
        for(Method method : methods){
            // 方法名称是否匹配
            if(method.getName().equals(rpcInvocation.getTargetMethod())){
                // 有没有返回值，没有的话，直接执行即可
                if(method.getReturnType().equals(Void.TYPE)){
                    method.invoke(aimObject, rpcInvocation.getArgs());
                }
                else {
                    // 执行有返回值的，需要把返回值塞回去
                    result = method.invoke(aimObject, rpcInvocation.getArgs());
                }
                break;
            }
        }
        // 把结果塞回去
        rpcInvocation.setResponse(result);
        // 把数据再包装为协议格式
        RpcProtocol respRpcProtocol = new RpcProtocol(JSON.toJSONString(rpcInvocation).getBytes());
        // 写回去
        ctx.writeAndFlush(respRpcProtocol);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        Channel channel = ctx.channel();
        if (channel.isActive()) {
            ctx.close();
        }
    }
}
